home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Languages / Oberon⁄F™ 1.1 / Obx / Mod / BlackBox (.txt) next >
Encoding:
Oberon Document  |  1995-08-09  |  13.9 KB  |  445 lines  |  [oODC/obnF]

  1. Documents.StdDocumentDesc
  2. Documents.DocumentDesc
  3. Containers.ViewDesc
  4. Views.ViewDesc
  5. Stores.StoreDesc
  6. Documents.ModelDesc
  7. Containers.ModelDesc
  8. Models.ModelDesc
  9. Stores.ElemDesc
  10. TextViews.StdViewDesc
  11. TextViews.ViewDesc
  12. TextModels.StdModelDesc
  13. TextModels.ModelDesc
  14. TextModels.AttributesDesc
  15. Helvetica
  16. Helvetica
  17. Helvetica
  18. MODULE ObxBlackBox;
  19.     IMPORT Kernel, Ports, Stores, Models, Views, Controllers, Properties, Fonts, Dialog;
  20.     CONST 
  21.         minded = -3; marked = -4; markedAndMinded = -7;    (* inside marks *)
  22.         absorbed = -1; reflected = -2;    (* outside marks *)
  23.         version = 0;
  24.     TYPE
  25.         Model = POINTER TO RECORD (Models.ModelDesc)
  26.             board : POINTER TO ARRAY OF ARRAY OF SHORTINT;
  27.             m, (* size of board *)
  28.             p, (* number of atoms *)
  29.             n, (* number of actual guess *)
  30.             score: INTEGER; 
  31.             showsol: BOOLEAN;
  32.         END;
  33.         Path = POINTER TO RECORD
  34.             i, j: INTEGER; next: Path
  35.         END;
  36.         View = POINTER TO RECORD (Views.ViewDesc)
  37.             mod: Model;
  38.             i, j: INTEGER;
  39.             d: LONGINT;
  40.             font: Fonts.Font
  41.         END;
  42.         UpdateMsg = RECORD (Models.UpdateMsg) END;
  43.     VAR 
  44.         para*: RECORD
  45.             nrOfAtoms*, boardSize*: INTEGER
  46.         END;
  47.         seed: LONGINT;
  48.     PROCEDURE UniRand (): REAL;
  49.         CONST a = 16807; m = 2147483647; q = m DIV a; r = m MOD a;
  50.     BEGIN
  51.         seed := a*(seed MOD q) - r*(seed DIV q);
  52.         IF seed <= 0 THEN seed := seed + m END;
  53.         RETURN seed * (1.0/m)
  54.     END UniRand;
  55.     (* problem-specific part *)
  56.     PROCEDURE Atom (m: Model; i,j: INTEGER): BOOLEAN;
  57.         VAR b: SHORTINT;
  58.     BEGIN
  59.         b := m.board[i,j]; RETURN (b = minded) OR (b = markedAndMinded)
  60.     END Atom;
  61.     PROCEDURE Marked (m: Model; i,j: INTEGER): BOOLEAN;
  62.         VAR b: SHORTINT;
  63.     BEGIN
  64.         b := m.board[i,j]; RETURN (b = marked) OR (b = markedAndMinded)
  65.     END Marked;
  66.     PROCEDURE Shoot (m: Model; i1, j1: INTEGER);
  67.         VAR i, j, d, di, dj : INTEGER;
  68.     BEGIN
  69.         IF j1 = 0 THEN di := 0; dj := 1
  70.         ELSIF j1 = m.m+1 THEN di := 0; dj := -1
  71.         ELSIF i1 = 0 THEN di := 1; dj := 0
  72.         ELSIF i1 = m.m+1 THEN di := -1; dj := 0
  73.         END; 
  74.         i := i1; j := j1;
  75.         IF ~Atom(m, i+di, j+dj) THEN
  76.             REPEAT
  77.                 IF Atom(m, i+di+dj, j+di+dj) THEN d := di; di := -dj; dj := -d
  78.                 ELSIF Atom(m,i+di-dj, j-di+dj) THEN d := di; di := dj; dj := d
  79.                 ELSE i := i+di; j := j+dj
  80.                 END
  81.             UNTIL (i=0) OR (i=m.m+1) OR (j=0) OR (j=m.m+1) OR Atom(m, i+di, j+dj);
  82.             IF (i=0) OR (i=m.m+1) OR (j=0) OR (j=m.m+1) THEN
  83.                 IF (i = i1) & (j = j1) THEN m.board[i1, j1] := reflected
  84.                 ELSE INC(m.n); m.board[i,j] := SHORT(m.n); m.board[i1,j1] := SHORT(m.n)
  85.                 END
  86.             ELSE m.board[i1,j1] := absorbed
  87.             END
  88.         ELSE m.board[i1,j1] := absorbed
  89.         END
  90.     END Shoot;
  91.     PROCEDURE GetPath (m: Model; i, j: INTEGER; VAR p: Path);
  92.         VAR d, di, dj : INTEGER;
  93.         PROCEDURE AddPoint(i, j: INTEGER); 
  94.             VAR q: Path;
  95.         BEGIN
  96.             IF (p = NIL) OR (p.i # i) OR (p.j # j) THEN NEW(q); q.i := i; q.j := j; q.next := p; p := q END
  97.         END AddPoint;
  98.     BEGIN
  99.         IF j = 0 THEN di := 0; dj := 1
  100.         ELSIF j = m.m+1 THEN di := 0; dj := -1
  101.         ELSIF i = 0 THEN di := 1; dj := 0
  102.         ELSIF i = m.m+1 THEN di := -1; dj := 0
  103.         END; 
  104.         IF ~Atom(m, i+di, j+dj) THEN AddPoint(i, j);
  105.             REPEAT
  106.                 IF Atom(m, i+di+dj, j+di+dj) THEN d := di; di := -dj; dj := -d; AddPoint(i, j)
  107.                 ELSIF Atom(m, i+di-dj, j-di+dj) THEN d := di; di := dj; dj := d; AddPoint(i, j)
  108.                 ELSE i := i+di; j := j+dj
  109.                 END;
  110.             UNTIL (i = 0) OR (i = m.m+1) OR (j = 0) OR (j = m.m+1) OR Atom(m, i+di, j+dj);
  111.             IF ~((i = 0) OR (i = m.m+1) OR (j = 0) OR (j = m.m+1)) THEN i := i+di; j := j+dj END;
  112.             AddPoint(i, j)
  113.         END
  114.     END GetPath;
  115.     PROCEDURE NewPuzzle (m: Model);
  116.         VAR i, j, k: INTEGER;
  117.     BEGIN
  118.         FOR i := 0 TO m.m+1 DO FOR j := 0 TO m.m+1 DO m.board[i,j] := 0 END END;        
  119.         k := 0;
  120.         WHILE k < m.p DO
  121.             i := 1 + SHORT(ENTIER(UniRand()*m.m));
  122.             j := 1 + SHORT(ENTIER(UniRand()*m.m));
  123.             IF ~Atom(m, i, j) THEN m.board[i,j] := minded; INC(k) END
  124.         END
  125.     END NewPuzzle;
  126.     PROCEDURE Score (m: Model): INTEGER;
  127.         VAR i, j, score, n: INTEGER;
  128.     BEGIN
  129.         score := 0; n := 0;
  130.         FOR i := 0 TO m.m + 1 DO
  131.             FOR j := 0 TO m.m + 1 DO
  132.                 IF (i = 0) OR (j = 0) OR (i = m.m+1) OR (j = m.m+1) THEN
  133.                     IF m.board[i,j] # 0 THEN INC(score) END
  134.                 ELSE
  135.                     IF Marked(m, i, j) THEN INC(n);
  136.                         IF ~Atom(m, i, j) THEN INC(score, 5) END
  137.                     END
  138.                 END
  139.             END
  140.         END;
  141.         IF n < m.p THEN INC(score, 5 * (m.p - n)) END;
  142.         RETURN score
  143.     END Score;
  144.     (* graphics part *)
  145.     PROCEDURE IntToString (x: LONGINT; VAR s: ARRAY OF CHAR);
  146.         VAR j, k: INTEGER; a: ARRAY 32 OF CHAR;
  147.     BEGIN
  148.         j := 0; REPEAT a[j] := CHR(x MOD 10 + ORD("0")); x := x DIV 10; INC(j) UNTIL x = 0;
  149.         k := 0; REPEAT DEC(j); s[k] := a[j]; INC(k) UNTIL j = 0;
  150.         s[k] := 0X
  151.     END IntToString;
  152.     PROCEDURE DrawStringCentered (v: View; f: Ports.Frame; x, y: LONGINT; s: ARRAY OF CHAR);
  153.     BEGIN
  154.         f.DrawString(x - v.font.StringWidth(s) DIV 2, y + v.font.asc DIV 2, Ports.black, s, v.font)
  155.     END DrawStringCentered;
  156.     PROCEDURE GetCoord (v: View; i, j: INTEGER; VAR x, y: LONGINT);
  157.         VAR w, h: LONGINT;
  158.     BEGIN
  159.         y := j * v.d + v.d DIV 2 + 1;
  160.         x := i * v.d + v.d DIV 2 + 1;
  161.         IF i = 0 THEN INC(x, v.d DIV 2)
  162.         ELSIF i = v.mod.m+1 THEN DEC(x, v.d DIV 2)
  163.         ELSIF j = 0 THEN INC(y, v.d DIV 2)
  164.         ELSIF j = v.mod.m+1 THEN DEC(y, v.d DIV 2)
  165.         END
  166.     END GetCoord;
  167.     (* Model *)
  168.     PROCEDURE Init (m: Model);
  169.     BEGIN
  170.         m.m := para.boardSize; m.p := para.nrOfAtoms;
  171.         NEW(m.board, m.m+2, m.m+2); NewPuzzle(m);
  172.         m.n := 0; m.score := 0; m.showsol := FALSE
  173.     END Init;
  174.     PROCEDURE (m: Model) Externalize (VAR wr: Stores.Writer);
  175.         VAR i, j: INTEGER;
  176.     BEGIN
  177.         m.Externalize^(wr);
  178.         wr.WriteVersion(version);
  179.         wr.WriteInt(m.m);
  180.         wr.WriteInt(m.p);
  181.         wr.WriteInt(m.n);
  182.         wr.WriteInt(m.score);
  183.         wr.WriteBool(m.showsol);
  184.         FOR i := 0 TO m.m+1 DO
  185.             FOR j := 0 TO m.m+1 DO
  186.                 wr.WriteSInt(m.board[i,j])
  187.             END
  188.         END
  189.     END Externalize;
  190.     PROCEDURE (m: Model) Internalize (VAR rd: Stores.Reader);
  191.         VAR ver: SHORTINT; x0: LONGINT; i, j: INTEGER;
  192.     BEGIN
  193.         m.Internalize^(rd);
  194.         IF ~rd.cancelled THEN
  195.             rd.ReadVersion(version, version, ver);
  196.             IF ~rd.cancelled THEN
  197.                 rd.ReadInt(m.m);
  198.                 rd.ReadInt(m.p);
  199.                 rd.ReadInt(m.n);
  200.                 rd.ReadInt(m.score);
  201.                 rd.ReadBool(m.showsol);
  202.                 NEW(m.board, m.m+2, m.m+2);
  203.                 FOR i := 0 TO m.m+1 DO
  204.                     FOR j := 0 TO m.m+1 DO
  205.                         rd.ReadSInt(m.board[i,j])
  206.                     END
  207.                 END
  208.             END
  209.         END
  210.     END Internalize;
  211.     PROCEDURE (m: Model) CopyAllFrom (source: Models.Model);
  212.         VAR i, j: INTEGER;
  213.     BEGIN
  214.         WITH source: Model DO
  215.             Init(m);
  216.             m.m := source.m; NEW(m.board, m.m+2, m.m+2);
  217.             m.n := source.n; m.p := source.p;
  218.             m.score := source.score; m.showsol := source.showsol;
  219.             FOR i := 0 TO m.m+1 DO
  220.                 FOR j := 0 TO m.m+1 DO m.board[i,j] := source.board[i,j] END
  221.             END
  222.         END
  223.     END CopyAllFrom;
  224.     PROCEDURE (m: Model) InitFrom (source: Models.Model);
  225.     BEGIN
  226.         Init(m)
  227.     END InitFrom;
  228.     (* View *)
  229.     PROCEDURE (v: View) Externalize (VAR wr: Stores.Writer);
  230.         VAR i, j: INTEGER;
  231.     BEGIN
  232.         v.Externalize^(wr);
  233.         wr.WriteVersion(version);
  234.         wr.WriteInt(v.i);
  235.         wr.WriteInt(v.j);
  236.         wr.WriteStore(v.mod)        
  237.     END Externalize;
  238.     PROCEDURE (v: View) Internalize (VAR rd: Stores.Reader);
  239.         VAR ver: SHORTINT; s: Stores.Store;
  240.     BEGIN
  241.         v.Internalize^(rd);
  242.         IF ~rd.cancelled THEN
  243.             rd.ReadVersion(version, version, ver);
  244.             IF ~rd.cancelled THEN
  245.                 rd.ReadInt(v.i);
  246.                 rd.ReadInt(v.j);
  247.                 rd.ReadStore(s); ASSERT(s # NIL, 100);
  248.                 IF s IS Model THEN
  249.                     v.mod := s(Model)
  250.                 ELSE
  251.                     rd.TurnIntoAlien(Stores.alienComponent)
  252.                 END;
  253.                 v.d := 0; 
  254.                 v.font := NIL
  255.             END
  256.         END
  257.     END Internalize;
  258.     PROCEDURE (v: View) CopyFrom (source: Views.View);
  259.     BEGIN
  260.         v.CopyFrom^(source);
  261.         WITH source: View DO
  262.             v.i := source.i; v.j := source.j; v.d := source.d; v.font := source.font
  263.         END
  264.     END CopyFrom;
  265.     PROCEDURE (v: View) InitModel (m: Models.Model);
  266.     BEGIN
  267.         v.mod := m(Model)
  268.     END InitModel;
  269.     PROCEDURE (v: View) ThisModel (): Models.Model;
  270.     BEGIN
  271.         RETURN v.mod
  272.     END ThisModel;
  273.     PROCEDURE (v: View) Restore (f: Views.Frame; l, t, r, b: LONGINT);
  274.         VAR w, h, d, x, y, x1, y1: LONGINT; i, j: INTEGER; p: Path; s: ARRAY 16 OF CHAR;
  275.     BEGIN
  276.         v.context.GetSize(w, h); d := w DIV (v.mod.m + 2);
  277.         IF (v.font = NIL) OR (v.d # d) THEN
  278.             v.d := d; v.font := Fonts.dir.This("Chicago", d * 2 DIV 3, {}, Fonts.normal)
  279.         END;
  280.         FOR i := 1 TO v.mod.m+1 DO
  281.             f.DrawLine(d, i*d,w-d, i*d, f.unit, 0);
  282.             f.DrawLine(i*d, d, i*d,w-d, f.unit, 0)
  283.         END;
  284.         FOR i := 0 TO v.mod.m+1 DO
  285.             FOR j := 0 TO v.mod.m+1 DO
  286.                 x := i * d + d DIV 2; y := j * d + d DIV 2;
  287.                 IF (i = 0) OR (i = v.mod.m+1) OR (j = 0) OR (j = v.mod.m+1) THEN
  288.                     IF v.mod.board[i,j] = absorbed THEN DrawStringCentered(v, f, x, y, "A")
  289.                     ELSIF v.mod.board[i,j] = reflected THEN DrawStringCentered(v, f, x, y, "R")
  290.                     ELSIF v.mod.board[i,j] > 0 THEN
  291.                         IntToString(v.mod.board[i,j], s); DrawStringCentered(v, f, x, y, s)
  292.                     END
  293.                 ELSE
  294.                     IF Marked(v.mod, i, j) THEN r := (9 * d) DIV 20;
  295.                         f.DrawOval(x-r, y-r, x+r, y+r, Ports.fill, Ports.black)
  296.                     END;
  297.                     IF v.mod.showsol & Atom(v.mod, i, j) THEN r := d DIV 3;
  298.                         IF Marked(v.mod, i, j) THEN f.DrawOval(x-r, y-r, x+r, y+r, Ports.fill, Ports.white)
  299.                         ELSE f.DrawOval(x-r, y-r, x+r, y+r, Ports.fill, Ports.black)
  300.                         END
  301.                     END
  302.                 END
  303.             END
  304.         END;
  305.         IF (v.i > 0) OR (v.j > 0) THEN
  306.             GetPath(v.mod, v.i, v.j, p);
  307.             IF p # NIL THEN
  308.                 GetCoord(v, p.i, p.j, x, y); p := p.next;
  309.                 WHILE p # NIL DO
  310.                     GetCoord(v, p.i, p.j, x1, y1);
  311.                     f.DrawLine(x, y, x1, y1, 2*f.unit, 0); x := x1; y := y1; p := p.next
  312.                 END
  313.             END
  314.         END;
  315.         IntToString(v.mod.p, s);
  316.         x := d; y := (v.mod.m+2)*d + (d+v.font.asc) DIV 2;
  317.         f.DrawString(x, y, Ports.black, "Atoms: ", v.font);  x := x + v.font.StringWidth("Atoms: ");
  318.         f.DrawString(x, y, Ports.black, s, v.font); 
  319.         IF v.mod.showsol THEN x := x + v.font.StringWidth(s);
  320.             f.DrawString(x, y, Ports.black, "  Score: ", v.font); x := x + v.font.StringWidth("  Score: ");
  321.             IntToString(v.mod.score, s); f.DrawString(x, y, Ports.black, s, v.font); 
  322.         END
  323.     END Restore;
  324.     PROCEDURE Track (v: View; f: Views.Frame; x, y: LONGINT; buttons: SET);
  325.         VAR i, j: INTEGER; w, h: LONGINT; msg: UpdateMsg; p: Path;
  326.     BEGIN
  327.         i := SHORT(x DIV v.d); j := SHORT(y DIV v.d);
  328.         IF (i > 0) & (i <= v.mod.m) & (j > 0) & (j <= v.mod.m) THEN    (* inside *)
  329.             IF Marked(v.mod, i, j) THEN INC(v.mod.board[i,j], 4)
  330.             ELSE DEC(v.mod.board[i,j], 4) 
  331.             END;
  332.         ELSIF ((i = 0) OR (i = v.mod.m + 1)) & (j > 0) & (j <= v.mod.m)
  333.         OR ((j = 0) OR (j  = v.mod.m + 1)) & (i > 0) & (i <= v.mod.m) THEN
  334.             IF v.mod.board[i,j] = 0 THEN Shoot(v.mod, i, j) END;
  335.             IF v.mod.showsol THEN
  336.                 IF Controllers.modify IN buttons THEN v.i := i; v.j := j ELSE v.i := 0; v.j := 0 END
  337.             END
  338.         END;
  339.         Models.Broadcast(v.mod, msg)
  340.     END Track;
  341.     PROCEDURE (v: View) HandleModelMsg (VAR msg: Models.Message);
  342.         VAR w, h: LONGINT;
  343.     BEGIN
  344.         WITH msg: UpdateMsg DO
  345.             IF ~v.mod.showsol THEN v.i := 0; v.j := 0 END;    (* adjust view to change of model *)
  346.             v.context.GetSize(w, h); Views.UpdateIn(v, 0, 0, w, h,  Views.keepFrames)
  347.         ELSE
  348.         END
  349.     END HandleModelMsg;
  350.     PROCEDURE (v: View) HandleCtrlMsg (f: Views.Frame; VAR msg: Controllers.Message;
  351.                                                                                 VAR focus: Views.View);
  352.     BEGIN
  353.         WITH msg: Controllers.TrackMsg DO
  354.             Track(v, f, msg.x, msg.y, msg.modifiers)
  355.         | msg: Controllers.PollOpsMsg DO
  356.             msg.type := "ObxBlackBox.ViewDesc"
  357.         ELSE
  358.         END
  359.     END HandleCtrlMsg;
  360.     PROCEDURE (v: View) HandlePropMsg (VAR msg: Properties.Message);
  361.     BEGIN
  362.         WITH msg: Properties.SizePref DO
  363.             IF (msg.w > Views.undefined) & (msg.h > Views.undefined) THEN
  364.                 Properties.ProportionalConstraint(v.mod.m, v.mod.m+1,
  365.                                                                         msg.fixedW, msg.fixedH, msg.w, msg.h)
  366.             ELSE
  367.                 msg.w := 100*Ports.mm; msg.h := msg.w * (v.mod.m+1) DIV v.mod.m;
  368.             END;
  369.         | msg: Properties.FocusPref DO
  370.             msg.setFocus := TRUE
  371.         ELSE
  372.         END
  373.     END HandlePropMsg;
  374.     (* commands *)
  375.     PROCEDURE Deposit*;
  376.         VAR v: View; m: Model;
  377.     BEGIN
  378.         NEW(m); Init(m);
  379.         NEW(v); v.InitModel(m);
  380.         Views.Deposit(v)
  381.     END Deposit;
  382.     PROCEDURE ShowSolution*;
  383.         VAR v : Views.View; msg: UpdateMsg;
  384.     BEGIN
  385.         v := Controllers.FocusView();
  386.         IF v # NIL THEN
  387.             WITH v: View DO
  388.                 v.mod.showsol := TRUE; v.mod.score := Score(v.mod);
  389.                 Models.Broadcast(v.mod, msg)
  390.             END
  391.         END
  392.     END ShowSolution;
  393.     PROCEDURE ShowSolutionGuard* (VAR par: Dialog.Par);
  394.         VAR v: Views.View;
  395.     BEGIN
  396.         v := Controllers.FocusView();
  397.         par.disabled := (v = NIL) OR ~(v IS View) OR v(View).mod.showsol
  398.     END ShowSolutionGuard;
  399.     PROCEDURE New*;
  400.         VAR v: Views.View; msg: UpdateMsg;
  401.     BEGIN
  402.         v := Controllers.FocusView();
  403.         IF v # NIL THEN
  404.             WITH v: View DO
  405.                 NewPuzzle(v.mod);
  406.                 v.mod.n := 0; v.mod.score := 0; v.mod.showsol := FALSE;
  407.                 v.i := 0; v.j := 0;
  408.                 Models.Broadcast(v.mod, msg)
  409.             END
  410.         END        
  411.     END New;
  412.     PROCEDURE Set*;
  413.         VAR v : Views.View; msg: UpdateMsg; i, j: INTEGER;
  414.     BEGIN
  415.         v := Controllers.FocusView();
  416.         IF v # NIL THEN
  417.             WITH v: View DO v.mod.p := 0;
  418.                 FOR i := 0 TO v.mod.m + 1 DO
  419.                     FOR j := 0 TO v.mod.m + 1 DO
  420.                         IF Marked(v.mod, i, j) THEN INC(v.mod.p); v.mod.board[i,j] := minded
  421.                         ELSE v.mod.board[i,j] := 0
  422.                         END
  423.                     END
  424.                 END;
  425.                 v.mod.n := 0; v.mod.score := 0; v.mod.showsol := FALSE;
  426.                 v.i := 0; v.j := 0;
  427.                 Models.Broadcast(v.mod, msg)
  428.             END
  429.         END        
  430.     END Set;
  431. BEGIN
  432.     seed := Kernel.Time(); para.boardSize := 8; para.nrOfAtoms := 4
  433. END ObxBlackBox.
  434. TextControllers.StdCtrlDesc
  435. TextControllers.ControllerDesc
  436. Containers.ControllerDesc
  437. Controllers.ControllerDesc
  438. TextRulers.StdRulerDesc
  439. TextRulers.RulerDesc
  440. TextRulers.StdStyleDesc
  441. TextRulers.StyleDesc
  442. TextRulers.AttributesDesc
  443. Helvetica
  444. Documents.ControllerDesc
  445.